# [JS进阶]proto、prototype、继承三者的关系就这么简单

# 核心四句

  • 1、所有对象都有__proto__属性来标识自己所继承的原型;
  • 2、函数才有prototype属性;
  • 3、创建函数时,JS会为这个函数自动添加prototype属性,值是一个有 constructor 属性的对象;
  • 4、函数当作构造函数调用(通过new调用),JS会帮助创建构造函数的实例,实例通过设置自己的__proto__指向构造函数的prototype来实现继承;

# 实例解析

# 1、定义对象和函数

//字面量定义对象
let a = {};
//构造函数定义对象
let b = new Object();	
//定义函数
function f(){};
//函数作为构造函数创建实例
let c = new f();

# 2、输出比较

  在浏览器的控制台console中输入上述定义的对象和函数,进行_proto_和prototype的比较: 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

# 3、输出解析

# 1)所有对象都有__proto__属性来标识自己所继承的原型

  比教上述所有输出的截图:无论对象还是函数,所有的输出都含有__proto__,为什么函数也有__proto__呢?因为函数本质上是特殊的对象,所有函数也是有__proto__的;从中可以验证所有对象都有__proto__属性来标识自己所继承的原型 。为了验证函数也是对象可以使用instanceof进行判断:

Function instanceof Object // true
# 2)函数才有prototype属性

  上图中,只有fObject输出中才有prototype,说明他们都是函数,对于f我们很容易判断,因为在定义时就决定了它时函数的事实,但是Object也是函数吗?不妨同样使用instanceof进行判断:

Object instanceof Function // true

从结果我们可以得出:Object底层定义为函数,我们通过new关键字调用的时候,就将Object作为构造函数使用的。

# 3)创建函数时,JS会为这个函数自动添加prototype属性,值是一个有 constructor 属性的对象

在这里插入图片描述   输出函数f的prototype,其实质是一个包含constructor属性的对象

# 4)函数当作构造函数调用(通过new调用),JS会帮助创建构造函数的实例,实例通过设置自己的__proto__指向构造函数的prototype来实现继承

  这句话从本质上阐述了js中继承的实现,即通过构造函数创建实例对象,实例的__proto__其实指向其构造函数的prototye属性;同样,我们用代码来验证下:

a.__proto__ === Object.prototype  //true
b.__proto__ === Object.prototype  //true
c.__proto__ === f.prototype  //true

在这里插入图片描述 注意:字面量方式创建对象其底层也是通过new Object实现的,所有let a = {} 等价于 let a = new Object()

# 4、原型和继承图

在这里插入图片描述 上图为原型链图,我们对上图进行人为的分区处理,大致分为四个区域,我们不妨将上面的分析和核心四句原型链图对应起来理解:

  • 1、Function instanceof Object // true Object instanceof Function // true区域1 ),当然到底是先有鸡还是先有蛋的探究这里就不深入了;
  • 2、对最底层Object继续进行原型跟踪,最终__proto__为null区域1 );
  • 3、定义的函数通过new关键字调用,生成新的函数实例的__proto__继承了构造函数.prototype区域2);
  • 4、函数的prototype属性的构造函数constructor指向函数本身(区域1,2,3
    f === f.prototype.constructor //true
    Function === Object.prototype.constructor //true
    Object === Object.prototype.constructor
    
    

# 5、小结

  在javascript中,通过__proto__和prototype的合作实现了原型链,以及对象的继承。另外,对于作为构造函数的函数而言,可以使用prototype存放要共享的属性和方法,也可以设置prototype指向现存的对象来继承该对象。   对于任何对象而言,其自身的__proto__指向自己构造函数的prototype属性,通过obj.proto.proto...一层一层的调用实现了原型链。其中包括操作符instanceof本质上是通过探测obj.proto.proto... 是否最终等于构造函数constructor.prototype来验证obj是否是构造函数constructor的实例。

在这里插入图片描述